package com.lnj.community.utiles;

import jakarta.annotation.PostConstruct;
import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

/**
 * 敏感词过滤器
 */
@Component
public class SensitiveUtile {

    private static final Logger logger = LoggerFactory.getLogger(SensitiveUtile.class);


    // 添加敏感词
    @PostConstruct
    public void init() {
        try (
                InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
                BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        ) {
            String keyword;
            while ((keyword = reader.readLine()) != null) {
                // 添加到前缀树
                this.addKeyword(keyword);
            }
        } catch (IOException e) {
            logger.error("加载敏感词文件失败: " + e.getMessage());
        }
    }

    private ACTrieNode root;

    public SensitiveUtile() {
        this.root = new ACTrieNode();
    }

    // 添加敏感词
    public void addKeyword(String keyword) {
        ACTrieNode current = root;
        for (char c : keyword.toCharArray()) {
            if (!current.getChildren().containsKey(c)) {
                current.getChildren().put(c, new ACTrieNode());
            }
            current = current.getChildren().get(c);
        }
        current.setEnd(true);
        current.setLength(keyword.length());
    }

    // 构建失败指针（BFS遍历）
    public void buildFailurePointer() {
        Queue<ACTrieNode> queue = new LinkedList<>();
        root.setFail(null);
        queue.offer(root);

        while (!queue.isEmpty()) {
            ACTrieNode current = queue.poll();

            for (Map.Entry<Character, ACTrieNode> entry : current.getChildren().entrySet()) {
                char key = entry.getKey();
                ACTrieNode child = entry.getValue();

                if (current == root) {
                    child.setFail(root);
                } else {
                    ACTrieNode failNode = current.getFail();
                    while (failNode != null) {
                        if (failNode.getChildren().containsKey(key)) {
                            child.setFail(failNode.getChildren().get(key));
                            break;
                        }
                        failNode = failNode.getFail();
                    }
                    if (failNode == null) {
                        child.setFail(root);
                    }
                }
                queue.offer(child);
            }
        }
    }

    // 过滤文本中的敏感词
    // 过滤文本中的敏感词（改进版）
    public String filter(String text) {
        if (StringUtils.isBlank(text)) {
            return text;
        }

        ACTrieNode current = root;
        char[] textChars = text.toCharArray();
        boolean[] sensitiveFlags = new boolean[textChars.length]; // 标记需要替换的位置

        for (int i = 0; i < textChars.length; i++) {
            char c = textChars[i];

            // 跳过符号但继续匹配
            if (isSymbol(c)) {
                continue;
            }

            // 查找匹配
            while (current != root && !current.getChildren().containsKey(c)) {
                current = current.getFail();
            }

            if (current.getChildren().containsKey(c)) {
                current = current.getChildren().get(c);

                if (current.isEnd()) {
                    // 标记整个敏感词需要替换（包括中间可能被符号隔开的部分）
                    int start = i - current.getLength() + 1;
                    for (int j = start; j <= i; j++) {
                        if (!isSymbol(textChars[j])) {
                            sensitiveFlags[j] = true;
                        }
                    }
                    current = root;
                }
            } else {
                current = root;
            }
        }

        // 构建结果
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < textChars.length; i++) {
            if (sensitiveFlags[i]) {
                Random random = new Random();
                int length = random.nextInt(3) + 2; // 替换为随机长度的*
                for (int j = 0; j < length; j++) {
                    result.append('*');
                }
            } else {
                result.append(textChars[i]);
            }
        }

        return result.toString();
    }

    // 判断是否为符号
    private boolean isSymbol(Character c) {
        // 0x2E80~0x9FFF 是东亚文字范围
        return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
    }

    // 前缀树
    class ACTrieNode {
        // 子节点(key是下级字符，value是对应的节点)
        private Map<Character, ACTrieNode> children = new HashMap<>();
        // 失败指针
        private ACTrieNode fail;
        // 是否为敏感词结尾
        private boolean isEnd;
        // 敏感词长度（用于标记匹配到的敏感词长度）
        private int length;

        public Map<Character, ACTrieNode> getChildren() {
            return children;
        }

        public void setChildren(Map<Character, ACTrieNode> children) {
            this.children = children;
        }

        public ACTrieNode getFail() {
            return fail;
        }

        public void setFail(ACTrieNode fail) {
            this.fail = fail;
        }

        public boolean isEnd() {
            return isEnd;
        }

        public void setEnd(boolean end) {
            isEnd = end;
        }

        public int getLength() {
            return length;
        }

        public void setLength(int length) {
            this.length = length;
        }
    }

}
